'''
Author: duliang thinktanker@163.com
Date: 2024-06-22 00:10:48
LastEditors: thinktanker thinktanker@163.com
LastEditTime: 2024-06-28 21:44:01
FilePath: \sajj\sajjclick_2024.py
Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
'''
import ctypes
import os
import threading
import time
import tkinter
from tkinter.messagebox import *
import keyboard
import numpy as np
import pyautogui
from PIL import ImageGrab, Image  # 用于保存屏幕截图
from win32api import GetSystemMetrics
import win32gui, win32ui, win32con
import io
from threading import Thread
import subprocess
import platform
import sys
from webdata import *
import urllib3
import ssl
ssl.create_default_context = ssl._create_unverified_context
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# from sql import new_search

'''
设置远程还是本地参数
'''

# paddle.set_device("gpu")
# os.environ['FLAGS_eager_delete_tensor_gb'] = "0.0"
# 模型路径下必须含有model和params文件，如果没有，现在可以自动下载了，不过是最简单的模型
# use_gpu 如果paddle是GPU版本请设置为 True

print("等待主程序载入")
# 窗口，显示器
dc = win32gui.GetDC(0)
dcObj = win32ui.CreateDCFromHandle(dc)
monitor = (0, 0, GetSystemMetrics(0), GetSystemMetrics(1))
hwnd_from_point = win32gui.WindowFromPoint((0, 0))
# 初始化
local_path = os.path.dirname(__file__)
sajj_handle = win32gui.FindWindow("Chrome_WidgetWin_0", "水安将军")
autoclick = os.path.exists(f"{local_path}{os.sep}appdata{os.sep}auto")
mark = os.path.exists(f"{local_path}{os.sep}appdata{os.sep}mark")
print(autoclick, mark)
REMOTE = os.path.exists(f"{local_path}{os.sep}remote")
HEDAERS = {
    'User-Agent':
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090819) XWEB/8555'
}
proxies = {
    'http': None,
    'https': None,
}

if REMOTE:
    import requests
    url = "http://223.68.11.42:8211/ocrsajj"
    url = "http://192.168.15.16:8211/ocrsajj"
    url = "https://cn-jn-lt-plustmp1.natfrp.cloud:14861/ocrsajj"
    # url = "http://dulht.320.io/ocrsajj"
else:
    from paddleocr import PaddleOCR
    cls_model_dir = "./whl/cls/ch/ch_ppocr_mobile_v2.0_cls_infer/"
    # --det_model_dir="./inference/ch_ppocr_mobile_v2.0_det_infer/"     # 检测模型所在文件夹
    det_model_dir = "./whl/det/ch/ch_PP-OCRv4_det_server_infer/"
    # --rec_model_dir="./inference/ch_ppocr_mobile_v2.0_rec_infer/"     # 识别模型所在文件夹
    rec_model_dir = "./whl/rec/ch/ch_PP-OCRv4_rec_server_infer/"
    ocr = PaddleOCR(use_angle_cls=False, 
                    use_gpu=True,
                    cls_model_dir=cls_model_dir,  #
                    det_model_dir=det_model_dir,  #
                    rec_model_dir=rec_model_dir,  #
    )

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False
def check_windows_version():
    release_info = platform.version()
    release_info = release_info.split(".")[-1]  # 去除可能存在的额外信息
    # print(release_info)

    # Windows 10 版本号通常包含 "10.", 而 Windows 11 版本号则有 "10." 也可能直接是 "21H2" 或其他标识
    if int(release_info) > 21000:
        return "win11"
    else:
        return "win10"
# 准确的坐标定义
def get_window_rect(hwnd):
    try:
        f = ctypes.windll.dwmapi.DwmGetWindowAttribute
    except WindowsError:
        f = None
    if f:
        rect = ctypes.wintypes.RECT()
        DWMWA_EXTENDED_FRAME_BOUNDS = 9
        f(ctypes.wintypes.HWND(hwnd),
          ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
          ctypes.byref(rect), ctypes.sizeof(rect))
        offset =(rect.bottom - rect.top) * 1.3 // 4
        print('窗口位置：{} {} {} {},偏移：{}'.format(
            rect.left, rect.top + (rect.bottom - rect.top) // 4, rect.right,
            rect.bottom,offset))
        return rect.left, rect.top + offset, rect.right, rect.bottom, offset


def snapshot(className=None, winName=None):
    '''
    可以后台截屏，但不能最小化窗口
    '''
    #获取后台窗口的句柄，注意后台窗口不能最小化
    try:
        hWnd = win32gui.FindWindow(className,
                                   winName)  #窗口的类名可以用Visual Studio的SPY++工具获取
        left, top, right, bot = win32gui.GetWindowRect(hWnd)
        width = right - left
        height = bot - top
        #返回句柄窗口的设备环境，覆盖整个窗口，包括非客户区，标题栏，菜单，边框
        hWndDC = win32gui.GetWindowDC(hWnd)
        #创建设备描述表
        mfcDC = win32ui.CreateDCFromHandle(hWndDC)
        #创建内存设备描述表
        saveDC = mfcDC.CreateCompatibleDC()
        #创建位图对象准备保存图片
        saveBitMap = win32ui.CreateBitmap()
        #为bitmap开辟存储空间
        saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
        #将截图保存到saveBitMap中
        saveDC.SelectObject(saveBitMap)
        #保存bitmap到内存设备描述表
        saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)
        ###获取位图信息
        bmpinfo = saveBitMap.GetInfo()
        bmpstr = saveBitMap.GetBitmapBits(True)
        #内存释放
        win32gui.DeleteObject(saveBitMap.GetHandle())
        saveDC.DeleteDC()
        mfcDC.DeleteDC()
        win32gui.ReleaseDC(hWnd, hWndDC)
        ###生成图像
        im_PIL = Image.frombuffer('RGB',
                                  (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
                                  bmpstr, 'raw', 'BGRX', 0, 1)
        im_PIL = im_PIL.convert('L')
        im_PIL.save(os.getcwd() + '/pil.jpg')  #保存
        return im_PIL
    except Exception as e:
        print(e)
        return None


def screen_thread():
    # threshold = 127
    while True:
        # keyboard.wait(hotkey="ctrl+alt+a")
        keyboard.wait(hotkey="space")
        now = time.time()
        try:
            left, top, right, bottom, offset = get_window_rect(sajj_handle)
            image = ImageGrab.grab(bbox=(left, top, right, bottom))
            # image = snapshot(className='Chrome_WidgetWin_0', winName="水安将军")
            if image:
                questionTxt = {"words_result": []}
                optionTxt = {"words_result": []}
                image = image.convert('L')
                image.save("test1.jpeg")
                binary = []
                for i in range(256):
                    if i < 125:
                        binary.append(0)
                    else:
                        binary.append(1)
                image = image.point(binary, '1')
                image.save("test2.jpeg")
                results = None
                if REMOTE:
                    imgBytes1 = io.BytesIO()                
                    image.save(imgBytes1, format="jpeg")
                    resp = requests.post(url=url,
                                        headers=HEDAERS,
                                        files={"imgbin": imgBytes1.getvalue()},
                                        verify=False,
                                        proxies=proxies
                                        # proxies=proxies
                                        )
                    if resp.status_code == 200:
                        results = resp.json()
                        if results:
                            results = results[0]
                            print(results)
                else:
                    img_convert_ndarray = np.array(image)
                    results = ocr.ocr(img_convert_ndarray)[0]
                if not results:
                    print("图片未载入")
                    continue
                # 第一条与第二条之间的行距
                h1 = results[1][0][-1][-1] - results[0][0][-1][-1]
                print('h1->',results[1][0][-1][-1] ,results[0][0][-1][-1],h1)
                questionTxt["words_result"].append({"words": results[0][-1][0]}) 
                for i in range(2, len(results)):                
                    # 间隔行距
                    h2 = results[i][0][-1][-1] - results[i - 1][0][-1][-1]
                    print('h2->',results[i][0][-1][-1] ,results[i - 1][0][-1][-1],h2)
                    # if h2 > h1 or h1 > h2*2:
                    try:
                        h2_h1 = round(h2 / h1) if h2 > h1 else round(h1 / h2)
                        if h2_h1>1 :
                            # print("下面是选项:", results[i:])
                            for answerList in results[i-1:]:
                                # print(answerList[1][0])
                                # print(answerList[0][0][0])
                                optionTxt['words_result'].append({
                                    'words':
                                    answerList[1][0],
                                    "location": {
                                        'top': answerList[0][0][1],
                                        'left': answerList[0][0][0],
                                        'width':
                                        answerList[0][1][0] - answerList[0][0][0],
                                        'height':
                                        answerList[0][2][1] - answerList[0][1][1]
                                    }
                                })
                            break
                        else:
                            questionTxt["words_result"].append(
                                {"words": results[i][-1][0]})
                    except Exception as e:
                        print(e)
                        if 'zero' in str(e):
                            questionTxt["words_result"].append(
                                {"words": results[i-1][-1][0]})
                    finally:
                        h1 = results[i][0][-1][-1] - results[i-1][0][-1][-1]
                        print('h1->',results[i][0][-1][-1] ,results[i-1][0][-1][-1],h1)
                        
                # print(questionTxt)
                # print(optionTxt)
                x, y = new_search(questionTxt, optionTxt, titile_text, answer_text,
                                True)
                if x:
                    left, top, right, bottom = win32gui.GetWindowRect(sajj_handle)
                    # 输出坐标信息
                    # print('窗口左上角坐标：({}, {})'.format(left, top))
                    # print('窗口右下角坐标：({}, {})'.format(right, bottom))
                    print(f'答案相对坐标：{x}，{y}')
                    # 鼠标目标坐标
                    targetX = left + x
                    targetY = top + y + offset
                    # 打开自动点击
                    if autoclick:
                        mouse_x, mouse_y = pyautogui.position()
                        pyautogui.moveTo(targetX, targetY)
                        print(mouse_x, mouse_y)
                        pyautogui.click()
                        pyautogui.moveTo(mouse_x, mouse_y)
                        # print('\033[32;40m 用时：', time.time() - now)
                        print(f"\033[0;31m{time.time() - now}\033[0m")
                    # 打开标记
                    if mark:
                        for _ in range(10):
                            # 画一个小白框
                            dcObj.Rectangle(
                                (int(targetX), int(targetY), int(targetX) + 50,
                                int(targetY) + 50))
                            time.sleep(0.01)
                            win32gui.InvalidateRect(hwnd_from_point, monitor,
                                                    True)  # 刷新显示器
        except Exception as e:
            print('屏幕识别失败：',e)
            

root = tkinter.Tk()
changeVar = tkinter.BooleanVar()
# checkTextVar = tkinter.StringVar()
changeVar.set(True)
# checkTextVar.set("每日答题")
sw = root.winfo_screenwidth()  # 得到屏幕宽度
sh = root.winfo_screenheight()  # 得到屏幕高度
# offset = sh // 8 + 200
# offset = sh // 8 + 30
root.title("水安将军辅助")
if sajj_handle:

    # def checkClick():
    #     if changeVar.get():
    #         checkTextVar.set("每日答题")
    #     else:
    #         checkTextVar.set("挑战答题")

    root.title("按空格获取答案")
    left1, top1, right1, bottom1 = win32gui.GetWindowRect(sajj_handle)
    # root = tkinter.Tk()
    root.geometry(f"320x800+{left1+(right1-left1)}+{top1}")
    # check = tkinter.Checkbutton(root,
    #                             variable=changeVar,
    #                             textvariable=checkTextVar,
    #                             command=checkClick)
    # check.pack()
    titile_text = tkinter.Text(root, width=100, height=5)
    titile_text.pack()
    answer_text = tkinter.Text(root, width=100, font=("黑体", 30), fg="red")
    answer_text.pack()
    question = ""
    th = threading.Thread(target=screen_thread)
    # th.setDaemon(True)
    try:
        th.daemon = True
    except:
        th.setDaemon(True)
    th.start()
    th1 = Thread(target=get_answers_web_data)
    th1.daemon = True
    th1.start()
    th2 = Thread(target=check_send_flag)
    th2.daemon = True
    th2.start()
    if check_windows_version() == 'win10':
        # 批处理文件路径
        bat_file_path = './config/00.bat'
    # else:
    #     bat_file_path = './config/00.bat'
  
        cmd = [
        'powershell', '-Command', f'Start-Process -Verb RunAs "{bat_file_path}"'
    ]
        # cmd = [
        #     'cmd', '/c', f'start /b "{bat_file_path}"'
        # ]
        if not is_admin():
            print("开启管理员权限")
            params = ' '.join(cmd)
            ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable,
                                                params, None, 1)
        try:
            subprocess.run(cmd, check=True)
        except subprocess.CalledProcessError as e:
            print(f"Error: {e}")
    root.mainloop()
else:
    print("打开“水安将军”小程序才能使用")
    ww = 240
    wh = 120
    root.geometry("%dx%d+%d+%d" % (ww, wh, sw // 3, sh // 3))

    def close_window():
        root.destroy()

    label = tkinter.Label(root, text="请打开“水安将军”小程序后运行")
    label.pack(pady=10)

    button = tkinter.Button(root, text="关闭窗口", command=close_window)
    button.pack(pady=30)

    root.mainloop()
